/* eslint-disable no-extra-semi */
/* eslint-disable no-param-reassign */
/* eslint-disable no-console */
/* eslint-disable no-plusplus */

import { Config } from './config'
import { Builder } from './builder'
import { History } from './history'
import { exec as execCommand } from './command'
import { bindEventHandlers, unbindEventHandlers } from './event'
import {
  cleanCopy,
  isEmptyFilterToken,
  findListItem,
  findFilterItemByValue,
  findFilterItemByName,
  isSearchTermToken
} from './util'

export class FilteredSearchBox extends Builder {
  constructor($el, options) {
    const config = new Config(options)

    super()

    this.config = config
    this.text = config.text
    this.data = config.data()
    this.groups = config.groups
    this.filters = config.filters
    this.callback = config.callback

    this.input = ''
    this.store = {}
    this.active = false
    this.target = null
    this.targetValue = null
    this.history = new History(config.history)

    this.$el = $el
    this.$search = null
    this.$tokens = null
    this.$target = null
    this.$targetValues = null

    this.logger = {
      log: function () {}
    }
    if (options.debug) {
      this.logger = console
    }
    if (typeof this.data.search !== 'string') {
      this.data.search = ''
    }

    this.build()
    bindEventHandlers(this)
  }

  // 清空选择器的选项
  clearFilterValue() {
    var filter = this.target
    var $token = this.$target
    var values = this.data[filter.key]
    var $values = this.$targetValues.find('.value-container')

    if (filter.multiple && values) {
      $token.find('.value').each(function () {
        var i
        var value = $(this).data('value')
        if (typeof value === 'undefined') {
          return
        }
        value = value.toString()
        for (i = 0; i < values.length; ++i) {
          if (values[i].toString() === value) {
            values.splice(i, 1)
            break
          }
        }
      })
      if (values.length < 1) {
        delete this.data[filter.key]
      }
    } else {
      delete this.data[filter.key]
    }
    $values.remove()
    this.commit()
    this.buildFilterDropdown(filter)
  }

  /**
   * 清除筛选器依赖表里的筛选器
   * 一个筛选器被其它筛选器依赖后，当这个筛选器的值被改变时，其它依赖筛选器也需要清除
   * @param {Object} filterKey 筛选器标识
   * @returns {Number} 清除的筛选器的数量
   */
  clearRequiredFilters(filterKey) {
    var that = this
    var count = 0

    that.filters.forEach(function (f) {
      if (f.requires instanceof Array) {
        if (f.requires.indexOf(filterKey) >= 0) {
          that.removeFilter(f.key)
          count += 1
        }
      }
    })
    return count
  }

  /**
   * 为筛选选器选择一个选项
   * @param {String} value 选项值
   * @returns {Boolean} 是否成功选中
   */
  selectFilterValue(value) {
    var html
    var filter = this.target
    var $values = this.$targetValues
    var values = this.data[filter.key]

    if (!$values) {
      return false
    }
    if (filter.multiple) {
      if ((values instanceof Array) && values.indexOf(value.toString()) >= 0) {
        return false
      }
    } else if (values === value.toString()) {
      return false
    }
    html = this.renderFilterTokenValue(filter, value)
    if (html) {
      $values.append(html)
      if (filter.multiple) {
        if (this.data[filter.key] instanceof Array) {
          this.data[filter.key].push(value)
        } else {
          this.data[filter.key] = [value]
        }
      } else {
        this.data[filter.key] = value
      }
      this.clearRequiredFilters(filter.key)
      this.commit()
      return true
    }
    return false
  }

  /**
   * 移除当前筛选器中的一个选项标记
   * @param {jQuery} $token 筛选器标记
   * @param {String} value 筛选选项值
   * @returns {Boolean} 是否移除成功
   */
  removeFilterValue($token, value) {
    var values
    var filter

    filter = this.getFilterByKey($token.data('key'))
    if (!filter) {
      return false
    }
    $token.find('.value[data-value="' + value + '"]').parent().remove()
    values = this.data[filter.key]
    if (filter.multiple) {
      value = value.toString()
      values.some(function (v, i) {
        if (v.toString() === value) {
          values.splice(i, 1)
          return true
        }
        return false
      })
    } else {
      delete this.data[filter.key]
    }
    if (isEmptyFilterToken($token)) {
      // 如果不是当前正编辑的筛选条件，则移除筛选器并取消编辑对象
      if (!this.target || this.target.key !== filter.key) {
        this.removeFilterToken($token)
        this.clearTargetFilter()
      }
    }
    this.clearRequiredFilters(filter.key)
    this.buildInputDropdown()
    this.commit()
    return true
  }

  doRemoveFilter(filterKey) {
    var $token

    delete this.data[filterKey]
    $token = this.$el.find('.js-visual-token[data-key="' + filterKey + '"]')
    $token.remove()
  }

  removeFilter(filterKey) {
    this.doRemoveFilter(filterKey)
    this.clearRequiredFilters(filterKey)
    this.buildInputDropdown()
    this.commit()
  }

  /**
   * 移除一个筛选器标记元素
   * @param {jQuery} $token 筛选器标记元素
   */
  removeFilterToken($token) {
    var key = $token.data('key')
    var values = this.data[key]
    var filter = this.getFilterByKey(key)

    if (!filter) {
      return false
    }
    if (filter.type === 'daterange') {
      delete this.data[key]
    } else if (filter.multiple && values) {
      $token.find('.value').each(function () {
        var i
        var value = $(this).data('value')
        if (typeof value === 'undefined') {
          return
        }
        value = value.toString()
        for (i = 0; i < values.length; ++i) {
          if (values[i].toString() === value) {
            values.splice(i, 1)
            break
          }
        }
      })
      if (values.length < 1) {
        delete this.data[key]
      }
    } else {
      delete this.data[key]
    }
    $token.remove()
    this.clearRequiredFilters(key)
    this.buildInputDropdown()
    this.commit()
    return true
  }

  newFilter(filterKey) {
    var $token
    var filter = null

    this.logger.log('newFilter()', filterKey)
    filter = this.getFilterByKey(filterKey)
    if (!filter || !this.visibleFilter(filter)) {
      return false
    }
    $token = this.$el.find('[data-key="' + filterKey + '"]')
    if ($token.length < 1) {
      $token = $(this.renderVisualToken(filter))
      $token.insertBefore(this.$inputDropdown)
    }
    this.selectFilterToken($token)
    this.updateState()
    return true
  }

  // 编辑搜索条件内容
  editTerm() {
    if (this.$search) {
      this.$search.remove()
    }
    this.$search = null
    this.buildInputDropdown()
    this.input = this.data.search
    this.data.search = ''
    this.$input.val(this.input)
    this.$input.focus()
  }

  /**
   * 编辑筛选器
   * @param {jQuery} $token 目标筛选器的标记元素
   * @returns {Boolean} 是否成功切换编辑状态
   */
  editFilter($token) {
    var filter = this.getFilterByKey($token.data('key'))
    if (this.target && this.target.key === filter.key) {
      this.$input.focus()
      return true
    }
    // 如果当前有正编辑的筛选器，则保存它
    if (this.targetValue) {
      const item = findFilterItemByName(this.target, this.targetValue)
      if (item) {
        this.selectFilterValue(item.value)
      }
    }
    this.logger.log('editFilter()')
    if (this.selectFilterToken($token)) {
      this.editCurrentFilterValue()
      return true
    }
    return false
  }

  editToken($token) {
    if (isSearchTermToken($token)) {
      this.editTerm()
    } else {
      this.editFilter($token)
    }
  }

  /**
   * 获取筛选器标记元素
   * @param {Object} filter 筛选器对象
   * @param {jQuery} $anchor 作为锚点的标记元素（可选），如果指定该参数，则会以它为起点，
   * 在它前面的元素中查找匹配的筛选器标记元素。
   */
  getFilterToken(filter, $anchor) {
    var $token
    var selector = '.js-visual-token[data-key="' + filter.key + '"]'

    if ($anchor) {
      $token = $anchor.prev(selector)
    } else {
      $token = this.$el.find(selector)
    }
    if ($token.length < 1) {
      return null
    }
    return $token.last()
  }

  /**
   * 取出指定筛选器的一个选项
   * @param {jQuery} $token 筛选器标记元素
   * @returns {String} 取出的选项内容，如果没有则返回 null
   */
  popFilterValue($token) {
    var value
    var item
    var filter = this.getFilterByKey($token.data('key'))

    if (!filter) {
      return null
    }
    if (filter.type === 'daterange') {
      $token.find('.value-container').remove()
      value = this.data[filter.key]
      delete this.data[filter.key]
    } else {
      if (filter.multiple) {
        value = this.data[filter.key].pop()
        $token.find('.value[data-value="' + value + '"]').parent().remove()
      } else {
        $token.find('.value-container').remove()
        value = this.data[filter.key]
        delete this.data[filter.key]
      }
      item = findFilterItemByValue(filter, value)
      if (item) {
        value = item.name
      } else if ((typeof filter.none === 'object')) {
        if (filter.none.value.toString() === value.toString()) {
          value = filter.none.name
        }
      }
    }
    this.logger.log('[' + filter.key + '] pop value:', value)
    return value
  }

  /**
   * 取出当前选中筛选器的一个选项
   * @returns {String} 取出的选项内容，如果没有则返回 null
   */
  popCurrentFilterValue() {
    return this.popFilterValue(this.$target)
  }

  /**
   * 取出当前选中筛选器的一个选项进行编辑
   * @returns {String} 取出的选项内容，如果没有则返回 null
   */
  editCurrentFilterValue() {
    var value = this.popCurrentFilterValue()

    if (!value) {
      return null
    }
    this.targetValue = value
    // 将输入框移动到目标筛选条件后面
    this.$inputDropdown.insertAfter(this.$target)
    this.buildInputDropdown()
    this.$input.val(value).focus()
    return value
  }

  /**
   * 选中一个筛选器，作为当前编辑对象
   * @param {jQuery} $token 筛选器标记元素
   * @return {Boolean} 是否选中成功
   */
  selectFilterToken($token) {
    var filter = this.getFilterByKey($token.data('key'))

    if (!filter) {
      return false
    }
    if (this.target) {
      if (this.target.key === filter.key) {
        return true
      }
    }

    this.input = ''
    this.target = filter
    this.$target = $token
    this.$targetValues = $token.find('.selectable')
    // 将输入框定位到筛选器标记元素的后面
    this.$inputDropdown.insertAfter($token)
    this.buildFilterDropdown(this.target)
    this.$input.focus()
    return true
  }

  clearTargetFilter() {
    var that = this
    var picker

    if (that.target) {
      if (isEmptyFilterToken(that.$target)) {
        that.$target.remove()
      }
      if (that.target.type === 'daterange') {
        picker = that.$input.data('daterangepicker')
        if (picker) {
          picker.remove()
        }
      }
      that.applyInput()
    }

    that.target = null
    that.targetValue = ''
    that.$target = null
    that.$targetValues = null
    that.buildInputDropdown()
  }

  /**
   * 从远程加载筛选器选项列表
   * @param {Object} filter 筛选器对象
   * @param {function} callback 加载完后的回调
   */
  loadFilterRemoteItems(filter, callback) {
    let store
    let cache
    let key = filter.key
    if (typeof filter.remote.params === 'function') {
      key = JSON.stringify(filter.remote.params(this.data))
    } else if (filter.remote.params) {
      key = JSON.stringify(filter.remote.params)
    }
    store = this.store[filter.key]
    if (typeof store !== 'object') {
      store = {
        cache: {}
      }
      this.store[filter.key] = store
    }
    store.key = key
    cache = store.cache[key]
    if (typeof cache !== 'object') {
      cache = {
        loading: true,
        items: []
      }
      store.cache[key] = cache
    }
    if (!cache.loading) {
      filter.items = cache.items
      this.logger.log('[' + filter.key + '] use cached items')
      if (callback) {
        callback()
      }
      return
    }
    if (Array.isArray(filter.remote)) {
      filter.items = []
      let items = []
      let load = 0
      filter.remote.forEach(item => {
        this.fetchItems(item, function (data) {
          if (typeof item.converter === 'function') {
            items = items.concat(item.converter(data))
          } else {
            items = items.concat(data)
          }

          load += 1
          if (load === filter.remote.length) {
            cache.items = items
            filter.items = items
            cache.loading = false
            if (callback) {
              callback()
            }
          }
        }, () => {
          store.loading = false
        })
      })
    } else {
      this.fetchItems(filter.remote,  (data) => {
        if (typeof filter.remote.converter === 'function') {
          cache.items = filter.remote.converter(data)
        } else {
          cache.items = data
        }
        cache.loading = false
        filter.items = cache.items
        if (callback) {
          callback()
        }
      }, () => {
        store.loading = false
      })
    }
  }

  fetchItems(remoteData, successCallback, failCallback) {
    var options = {
      url: remoteData.url
    }
    if (typeof remoteData.params === 'function') {
      options.data = remoteData.params(this.data)
    } else if (remoteData.params) {
      options.data = remoteData.params
    }
    var fetcher = function (ajaxOptions, onSuccess, onError) {
      return $.ajax(ajaxOptions).done(onSuccess).fail(onError)
    }
    if (typeof remoteData.fetcher === 'function') {
      fetcher = remoteData.fetcher
    }
    fetcher(options, (data) => {
      successCallback(data)
    }, function () {
      failCallback()
    })
  }

  getCurrentFilterItem(value) {
    if (this.target && this.checkFilterItemsLoaded(this.target)) {
      return findFilterItemByValue(this.target, value)
    }
    return false
  }

  execCommand(cmd) {
    return execCommand(this, cmd)
  }

  removeDateRangePicker() {
    var picker = this.$input.data('daterangepicker')

    if (picker) {
      picker.remove()
    }
    this.$input.off('apply.daterangepicker cancel.daterangepicker')
  }

  // 应用当前输入的内容，更新元素
  applyInput() {
    this.logger.log('applyInput()', this.input)
    if (this.data.search) {
      this.data.search += this.input
    } else {
      this.data.search = this.input
    }
    // 没有目标筛选器的话，就当成更新搜索条件
    if (!this.target) {
      this.buildSearchTerm()
    }
    this.$input.val('')
    this.input = ''
  }

  /**
   * 设置是否禁用此组件
   * @param {Boolean} disabled 是否禁用
   */
  setDisabled(disabled) {
    this.$input.prop('disabled', disabled)
    if (disabled) {
      this.active = false
      this.$el.addClass('disabled')
      this.$inputDropdown.addClass('disabled').dropdown('hide')
    } else {
      this.$el.removeClass('disabled')
      this.$inputDropdown.removeClass('disabled')
    }
  }

  getFilterByName(name) {
    return findListItem(this.filters, function (f) {
      return f.name === name
    })
  }

  getFilterByKey(key) {
    return findListItem(this.filters, function (f) {
      return f.key === key
    })
  }

  /**
   * 获取筛选器可用的选项列表
   * @param {Object} filter 筛选器对象
   */
  getFilterAvailableItems(filter) {
    var that = this
    var selectedItems = that.data[filter.key]

    if (typeof selectedItems === 'undefined' || selectedItems.length < 1) {
      return filter.items
    }
    // 如果是单选的筛选条件，只要选择一个选项，就不允许继续选了
    if (!filter.multiple) {
      return []
    }
    if (typeof filter.none === 'object') {
      if (selectedItems[0].toString() === filter.none.value.toString()) {
        return []
      }
    }
    return filter.items.filter(function (item) {
      return !selectedItems.some(function (selected) {
        return selected.toString() === item.value.toString()
      })
    })
  }

  /**
   * 检查筛选器选项列表是否已经加载完毕
   * @param {Object} filter 筛选器对象
   */
  checkFilterItemsLoaded(filter) {
    var cache
    var store = this.store[filter.key]

    if (typeof filter.remote !== 'object') {
      return true
    }
    if ((typeof store === 'object') && store.key) {
      cache = store.cache[store.key]
      if (typeof cache === 'object' && !cache.loading) {
        return true
      }
    }
    return false
  }

  // 检查筛选器的值是否有效（排除“none”值）
  checkFilterValue(filterKey) {
    var filter = this.getFilterByKey(filterKey)
    var value = this.data[filterKey]

    if (!value) {
      return false
    }
    if (typeof filter.none === 'object') {
      if (filter.multiple) {
        value = value[0]
      }
      if (value.toString() === filter.none.value.toString()) {
        return false
      }
    }
    return true
  }

  // 设置 tabs 选中
  setTabSelected() {
    for (let i = 0; i < this.target.tabs.length; i++) {
      if (this.$el.find(`.item[data-tab=${this.target.tabs[i].key}]`).not('.filtered').length) {
        this.$el.find(`.tab[data-tab=${this.target.tabs[i].key}]`).trigger('click')
        break
      }
    }
  }

  /**
   * 检查筛选器是否可见
   * 筛选器是否可见，取决于是否有可选的选项、是否满足依赖
   * @param {Object} filter 筛选器对象
   */
  visibleFilter(filter) {
    var i
    var value

    // 如果这个筛选器依赖其它筛选器
    if (filter.requires) {
      if (typeof filter.requires === 'string') {
        if (!this.checkFilterValue(filter.requires)) {
          return false
        }
      } else if (filter.requires instanceof Array) {
        for (i = 0; i < filter.requires.length; ++i) {
          if (!this.checkFilterValue(filter.requires[i])) {
            return false
          }
        }
      }
    }
    if (filter.type === 'daterange') {
      return !this.data[filter.key]
    }
    if (this.checkFilterItemsLoaded(filter)) {
      if (this.getFilterAvailableItems(filter).length > 0) {
        return true
      }
      if (typeof filter.none === 'object') {
        value = this.data[filter.key]
        if (!value || value.length < 1) {
          return true
        }
        if (filter.multiple) {
          return value.indexOf(filter.none.value.toString()) === -1
        }
        return value !== filter.none.value.toString()
      }
      return false
    }
    return true
  }

  isEmpty() {
    var that = this
    var emptyFilters = that.filters.every(function (filter) {
      var value = that.data[filter.key]
      return typeof value === 'undefined' || value.length < 1
    })
    return emptyFilters && !this.data.search && !this.input
  }

  // 更新输入框内的占位符
  updatePlaceholder() {
    if (!this.isEmpty() || this.target) {
      this.$input.attr('placeholder', '')
    } else {
      this.$input.attr('placeholder', this.text.placeholder)
    }
  }

  // 更新“清除”按钮的状态
  updateClearButton() {
    if (!this.isEmpty() || this.target || this.$input.val()) {
      this.$el.removeClass('is-empty')
    } else {
      this.$el.addClass('is-empty')
    }
  }

  focus() {
    this.$input.focus()
  }

  hasFocus() {
    if (this.active || this.$input.is(':focus')) {
      return true
    }
    return false
  }

  /**
   * 隐藏下拉菜单时的回调
   * @returns {Boolean} 是否需要隐藏
   */
  onHide() {
    return !this.hasFocus()
  }

  // 锁定显示一段时间，避免下拉框自动隐藏
  lockShow() {
    this.active = true
    // 功能与 deferFocusTime() 互斥，所以取消它的定时器
    if (this.timerForFocus) {
      clearTimeout(this.timerForFocus)
    }
    this.timerForFocus = setTimeout(() => { this.active = false }, 300)
  }

  // 延长焦点状态时间，避免在做一些操作时因取消焦点而导致下拉框自动隐藏
  deferFocusTime() {
    if (this.active && this.timerForFocus) {
      return
    }
    if (this.timerForFocus) {
      clearTimeout(this.timerForFocus)
    }
    this.active = true
    this.timerForFocus = setTimeout(() => {
      this.active = false
      // 如果输入框还未获得焦点，则隐藏下拉框
      if (!this.$input.is(':focus')) {
        this.$inputDropdown.dropdown('hide')
      }
    }, 200)
  }

  resetInputPosition() {
    // 如果已经在末尾，就不重复变动了，避免下拉框重复收起和展开
    if (this.$inputDropdown.is(':last-child')) {
      return
    }
    setTimeout(() => {
      // 移动输入框到筛选器列表的末尾
      this.$tokens.append(this.$inputDropdown)
    }, 400)
  }

  addHistory(data) {
    this.history.add(this.filters, data)
    this.buildInputDropdown()
  }

  generateHistoryItem(data) {
    return this.history.generateItem(this.filters, data)
  }

  submit() {
    var that = this
    var data = {}

    that.filters.forEach(function (f) {
      var value = that.data[f.key]
      if (typeof value !== 'undefined') {
        data[f.key] = that.data[f.key]
      }
    })
    that.applyInput()
    data.search = that.data.search
    that.callback(cleanCopy(data))
  }

  updateState() {
    this.updatePlaceholder()
    this.updateClearButton()
  }

  // 提交当前的改动
  commit() {
    this.updateState()
    this.$el.trigger('change.fsb', cleanCopy(this.data))
  }

  // 清除全部筛选器
  clear() {
    this.$el.find('.js-visual-token').remove()
    this.data = {}
    this.input = ''
    this.$input.val('')
    this.clearTargetFilter()
  }

  // 设置筛选器列表
  setFilters(filters) {
    var that = this
    var keys = filters.map(function (f) { return f.key })
    that.filters.forEach(function (f) {
      if (keys.indexOf(f.key) < 0) {
        that.removeFilter(f.key)
      }
    })
    that.clearTargetFilter()
    that.filters = filters
    that.filters.forEach(function (f) {
      // 如果该筛选器使用的是远程的选项列表，且之前已经有缓存选项列表，则恢复它
      if (typeof f.remote === 'object' && that.checkFilterItemsLoaded(f)) {
        that.loadFilterRemoteItems(f)
      }
    })
    that.buildInputDropdown()
  }

  /**
   * 设置选中的筛选条件
   * @param {Object} data 筛选条件数据
   */
  setData(data) {
    this.clear()
    this.data = data
    this.buildFilterTokens()
    this.buildInputDropdown()
    this.buildSearchTerm()
    this.updateState()
  }

  // 销毁组件
  destroy() {
    this.clear()
    this.$el.off('click')
    this.removeDateRangePicker()
    unbindEventHandlers()
  }
}

export default FilteredSearchBox
